package com.wontube.client.remote;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;

import com.wontube.client.conf.ServerEnvironment;
import com.wontube.client.io.IObjectProtocol;
import com.wontube.client.pub.ProxyRequest;
import com.wontube.client.pub.RequestHeaders;

/**
 * @author yuechao
 * 
 */
public final class ProxyClient {
	private String serverUrl = "";

	private boolean isDone = false;
	private String errorMsg = "";
	private String clientSessionId = "";

	private int connectTimeout = ServerEnvironment.environment.getDefaultConnectTimeout();
	private int readTimeout = ServerEnvironment.environment.getDefaultReadTimeout();
	private String apiVersion = ServerEnvironment.environment.getDefaultApiVersion();
	private String dataFormat = ServerEnvironment.environment.getDefaultDataFormat();
	private String agent = ServerEnvironment.environment.getDefaultAgent();
	private HashMap<String, String> headers = new HashMap<String, String>();
	private HashMap<String, String> requestExtHeaders = new HashMap<String, String>();

	public ProxyClient() {
	}
	
	public String getClientSessionId() {
		return this.clientSessionId;
	}

	public void setClientSessionId(String clientSessionId) {
		this.clientSessionId = clientSessionId;
	}

	/**
	 * 获取服务器地址，最后不含/
	 * 
	 * @return
	 */
	public String getServerUrl() {
		return this.serverUrl;
	}

	/**
	 * 设置服务器地址，最后不含/
	 * 
	 * @param url
	 */
	public void setServerUrl(String url) {
		this.serverUrl = url;
	}

	public String getRemoteUrl() {
		if (this.serverUrl == null || "".equals(this.serverUrl)) {
			return ServerEnvironment.environment.getRemoteUrl();
		}

		return this.serverUrl + "/main.handler";
	}

	/**
	 * @return the isDone
	 */
	public boolean isDone() {
		return this.isDone;
	}

	/**
	 * @param isDone
	 *            the isDone to set
	 */
	public void setDone(boolean isDone) {
		this.isDone = isDone;
	}

	/**
	 * @return the errorMsg
	 */
	public String getErrorMsg() {
		return this.errorMsg;
	}

	/**
	 * @param errorMsg
	 *            the errorMsg to set
	 */
	public void setErrorMsg(String errorMsg) {
		this.errorMsg = errorMsg;
	}

	public int getConnectTimeout() {
		return this.connectTimeout;
	}

	public void setConnectTimeout(int timeout) {
		this.connectTimeout = timeout;
	}

	public int getReadTimeout() {
		return this.readTimeout;
	}

	public void setReadTimeout(int value) {
		this.readTimeout = value;
	}
	
	public HashMap<String, String> getRequestExtHeaders() {
		return requestExtHeaders;
	}

	public void setRequestExtHeaders(HashMap<String, String> requestExtHeaders) {
		this.requestExtHeaders = requestExtHeaders;
	}

	public HashMap<String, String> getHeaders() {
		return this.headers;
	}

	public void setHeaders(HashMap<String, String> value) {
		this.headers = value;
	}

	public String getApiVersion() {
		return this.apiVersion;
	}

	public void setApiVersion(String apiVersion) {
		this.apiVersion = apiVersion;
	}

	public String getDataFormat() {
		return this.dataFormat;
	}

	public void setDataFormat(String dataFormat) {
		this.dataFormat = dataFormat;
	}
	
	public String getAgent() {
		return this.agent;
	}

	public void setAgent(String agent) {
		this.agent = agent;
	}

	public String invoke(IObjectProtocol protocol, String clazzName, String methodName, Object[] args)
			throws IOException {
		if (args == null) {
			args = new Object[0];
		}

		String[] arguments = new String[args.length];
		for (int i = 0; i < args.length; i++) {
			Object arg = args[i];
			arguments[i] = protocol.toProtoString(arg);
		}

		RequestHeaders headers = new RequestHeaders();
		String sessionId = this.clientSessionId;
		if (sessionId == null || "".equals(sessionId)) {
			sessionId = ServerEnvironment.lastClientSessionId;
		}
		headers.setSessionId(sessionId);
		headers.setClazzName(clazzName);
		headers.setMethodName(methodName);
		headers.setAgent(this.agent);
		headers.setApiVersion(this.apiVersion);
		headers.setDataFormat(this.dataFormat);
		headers.setExtHeaders(this.requestExtHeaders);

		ProxyRequest request = new ProxyRequest();
		request.setHeaders(headers);
		request.setArguments(arguments);

		String value = request.toJsonString();
		URL uri = new URL(this.getRemoteUrl());
		HttpURLConnection conn = (HttpURLConnection) uri.openConnection();
		conn.setDoOutput(true);
		conn.setDoInput(true);
		conn.setRequestMethod("POST");
		conn.setUseCaches(false);
		conn.setInstanceFollowRedirects(true);
		conn.setConnectTimeout(this.connectTimeout);
		conn.setReadTimeout(this.readTimeout);
		conn.setRequestProperty("Content-Type", "text/plain;charset=" + ServerEnvironment.charsetName);
		conn.connect();
		try {
			OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), ServerEnvironment.charsetName);
			try {
				writer.write(value);
				writer.flush();
			} finally {
				writer.close();
			}

			InputStreamReader reader = new InputStreamReader(conn.getInputStream(), ServerEnvironment.charsetName);
			StringBuilder sb = new StringBuilder();
			char[] cbuffer = new char[512];
			try {
				while (true) {
					int len = reader.read(cbuffer, 0, cbuffer.length);
					if (len <= 0) {
						break;
					}
					sb.append(cbuffer, 0, len);
				}
			} finally {
				reader.close();
			}
			return sb.toString();
		} finally {
			conn.disconnect();
		}
	}
}
